Skip to content

Conversation

@SaintPatrck
Copy link
Contributor

@SaintPatrck SaintPatrck commented Nov 11, 2025

🎟️ Tracking

PM-28086

📔 Objective

This PR introduces a new :testharness module - a standalone Android application for validating Bitwarden's Credential Manager provider implementation.

Purpose:
The test harness allows developers to exercise and verify all Credential Manager API operations that the Bitwarden app supports as a credential provider:

  • Password Operations: Create and retrieve password credentials via CreatePasswordRequest and GetPasswordOption
  • Passkey Operations: Create and retrieve passkeys via CreatePublicKeyCredentialRequest and GetPublicKeyCredentialOption
  • Combined Operations: Test hybrid flows that accept both passwords and passkeys

Architecture:
The module follows the same patterns as :app and :authenticator:

  • MVVM + UDF architecture with BaseViewModel
  • Hilt dependency injection throughout
  • Jetpack Compose UI with Material 3
  • Comprehensive unit test coverage (ViewModels, Screens, and data layer)

Integration:
The test harness acts as a credential consumer client, triggering the system credential picker and allowing selection of Bitwarden as the provider. This enables end-to-end validation of credential flows without relying on external websites or apps.

Build Configuration:
Added :testharness to detekt (static analysis) and kover (code coverage) configurations in root build.gradle.kts.

Requirements: API 28+ (uses AndroidX Credentials library with Play Services compatibility)

📸 Screenshots

Coming soon!

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@github-actions
Copy link
Contributor

github-actions bot commented Nov 11, 2025

Logo
Checkmarx One – Scan Summary & Detailsc87cde66-36da-4b29-a498-ed9fe95f5865

New Issues (21)

Checkmarx found the following issues in this Pull Request

Severity Issue Source File / Package Checkmarx Insight
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 429
detailsMethod Lambda at line 429 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: DEkQ77TFY5%2F3tTn9qOx3aVF8pnY%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 402
detailsMethod Lambda at line 402 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: iJjzbpf07ELkkvR2O%2BNKKAs7dfs%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 386
detailsMethod Lambda at line 386 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: h41Ovn2b7Uz%2B0KjrdHy4RJ2P5iE%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 334
detailsMethod Lambda at line 334 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: NiO1Ck8FafYoUom8Uba5CUIjkxs%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 305
detailsMethod Lambda at line 305 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: Qb%2Bfl9Ll3Vz8qERMBn2%2BPNcxHIU%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 265
detailsMethod Lambda at line 265 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: AzrtRwJIZXhwmPlNxN9RdYM%2Be6Y%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 237
detailsMethod Lambda at line 237 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: zdsbrS%2FdGx%2Fc0uAEoadEULN4j5c%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 170
detailsMethod Lambda at line 170 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: 1M9LksDFcsE1UpnaOozDrACySPo%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 206
detailsMethod Lambda at line 206 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: NewfGEHjcWfWJMtfc%2FUtSNF3cMw%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 110
detailsMethod Lambda at line 110 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest...
ID: yhGJwgkmcIrkSY2CuSqhVTkeidQ%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 90
detailsMethod Lambda at line 90 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest....
ID: kGojYCDFh5NwTDZ98KFwy0g1zdE%3D
Attack Vector
MEDIUM Privacy_Violation /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 70
detailsMethod Lambda at line 70 of /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest....
ID: u7oeUV%2BSZdBZTj0G1qer1bXYQ1M%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 254
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: XdWq2vQlWBMed4FBL5F95ZeRXNI%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 418
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: VpHFbGFlv1y9bcpHSB7zITFWuZM%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 321
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: y7WtY5BgHgAqMCAS%2FajYB01188g%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 292
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: HkVzOYz6wSQIoffve8l9xaDrits%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 223
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: Ir1R4Ojlts0FwPIQqfseX1PNAVs%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 192
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: EF9x7ZMbD0uW14pKWVIZPd37qJo%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 159
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: YTj%2Fe%2Fd6Gnyu6N7Kl5j4oWRkpyk%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 127
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: Ih7fts2b8M65TEG7f0CiGxmtpuU%3D
Attack Vector
MEDIUM Use_of_Hardcoded_Password /testharness/src/test/kotlin/com/bitwarden/testharness/ui/platform/feature/createpassword/CreatePasswordViewModelTest.kt: 54
detailsThe application uses the hard-coded password "SecurePassword123!" for authentication purposes, either using it to verify users' identities, or to...
ID: daA1Iq660j6qGBcYnvOG%2FE2Sryo%3D
Attack Vector

Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checkmarx One found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@SaintPatrck SaintPatrck changed the title Add testharness module for Credential Manager and Autofill e2e testing [PM-28086] Add testharness module for Credential Manager and Autofill e2e testing Nov 11, 2025
@SaintPatrck SaintPatrck changed the title [PM-28086] Add testharness module for Credential Manager and Autofill e2e testing [PM-28086] Add testharness module for Credential Manager and Autofill testing Nov 11, 2025
@SaintPatrck SaintPatrck changed the title [PM-28086] Add testharness module for Credential Manager and Autofill testing [PM-28086] Add testharness for Credential Manager and Autofill testing Nov 11, 2025
@codecov
Copy link

codecov bot commented Nov 12, 2025

Codecov Report

❌ Patch coverage is 94.41101% with 65 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.43%. Comparing base (7120eef) to head (e9670c6).
⚠️ Report is 24 commits behind head on main.

Files with missing lines Patch % Lines
...passwordorpasskey/GetPasswordOrPasskeyViewModel.kt 92.55% 3 Missing and 4 partials ⚠️
...rness/ui/platform/feature/rootnav/RootNavScreen.kt 65.00% 6 Missing and 1 partial ⚠️
...rness/ui/platform/feature/landing/LandingScreen.kt 86.95% 2 Missing and 4 partials ⚠️
...tform/feature/createpasskey/CreatePasskeyScreen.kt 95.06% 2 Missing and 2 partials ⚠️
...e/credentialmanager/CredentialManagerListScreen.kt 94.59% 2 Missing and 2 partials ⚠️
.../kotlin/com/bitwarden/testharness/MainViewModel.kt 62.50% 3 Missing ⚠️
.../testharness/data/manager/CredentialTestManager.kt 0.00% 3 Missing ⚠️
...form/feature/autofill/AutofillPlaceholderScreen.kt 83.33% 2 Missing and 1 partial ⚠️
...rm/feature/createpasskey/CreatePasskeyViewModel.kt 96.84% 1 Missing and 2 partials ⚠️
...orm/feature/createpassword/CreatePasswordScreen.kt 96.05% 2 Missing and 1 partial ⚠️
... and 9 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6159      +/-   ##
==========================================
+ Coverage   84.99%   85.43%   +0.44%     
==========================================
  Files         723      755      +32     
  Lines       52742    54064    +1322     
  Branches     7652     7790     +138     
==========================================
+ Hits        44827    46192    +1365     
+ Misses       5242     5166      -76     
- Partials     2673     2706      +33     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@SaintPatrck SaintPatrck marked this pull request as ready for review November 12, 2025 14:49
@claude
Copy link
Contributor

claude bot commented Nov 12, 2025

Claude finished @SaintPatrck's task —— View job


Code Review Complete

Overall Assessment: APPROVE with minor recommendations

The :testharness module is well-structured and follows established patterns from :app and :authenticator. Architecture compliance is strong (MVVM + UDF, Hilt DI, Compose UI). Test coverage is comprehensive at 94.4% patch coverage. Most issues raised by the human reviewer (david-livefront) remain unaddressed and should be considered before merge.


Critical Issues

Finding 1: PR Description Missing Screenshots
The PR objective mentions "Coming soon!" for screenshots but requires visual confirmation for UI validation per project requirements. Consider adding screenshots before merge.

Finding 2: Incomplete Resolution of Human Reviewer Feedback
Multiple code quality issues identified by david-livefront remain unresolved:

  • Date/time handling using hardcoded format "HH:mm:ss" (lines 160-164 in ViewModels)
  • Navigation patterns need extraction to separate destination functions
  • Edge-to-edge UI padding issues (navigationBarsPadding inside scrolling content)
  • String externalization (hardcoded "Back" string)
  • ViewModel reference inconsistency (some use remember(viewModel), some don't)

Finding 3: Author Dismissed Legitimate AndroidManifest Concern
Author marked as "intentional" the incomplete configChanges attribute. However, missing orientation|screenSize will cause activity recreation on rotation/multi-window changes, breaking state preservation despite SavedStateHandle usage. This contradicts standard Android practices.

See inline comment on AndroidManifest.xml:20 for required fix.


Architecture & Patterns

Strengths:

  • Follows MVVM + UDF pattern correctly with BaseViewModel
  • Proper Hilt dependency injection throughout
  • Type-safe navigation using sealed classes
  • Comprehensive unit test coverage (94.4%)
  • Good separation of concerns (data/ui layers)

💭 Finding 4: Date Format Pattern in ViewModels
All ViewModels use hardcoded "HH:mm:ss" format for timestamps. For a test harness, fixed format aids log parsing, but lacks documentation explaining this choice.

See inline comment on CreatePasswordViewModel.kt:160 for recommendation.

💭 Finding 5: Navigation Pattern Inconsistency
Per ARCHITECTURE.md example (line 449-455), destination functions should be extracted from graph functions for better testability and organization.

Current vs. Expected Pattern

Current (CredentialManagerListNavigation.kt:89-107):

fun NavGraphBuilder.credentialManagerGraph(...) {
    navigation<CredentialManagerGraphRoute>(...) {
        credentialManagerListDestination(...)  // ✅ Already extracted
        // other destinations
    }
}

This is actually following the pattern correctly. The human reviewer's concern about "inline composableWithRootPushTransitions block" was already addressed - credentialManagerListDestination is properly extracted on line 89.

Status: Already resolved in latest commit.


Code Quality

🎨 Finding 6: Edge-to-Edge UI Padding Placement
Spacer(Modifier.navigationBarsPadding()) inside scrolling Column causes padding to scroll with content, breaking edge-to-edge display.

See inline comment on CreatePasswordScreen.kt:148 for fix that applies to all screen files.

🎨 Finding 7: String Resource Usage Inconsistency
CreatePasswordScreen.kt:65 uses stringResource(BitwardenString.back) from :ui module, while testharness has its own strings.xml. Consider consistency.

Current: Mixing :ui module strings with testharness-specific strings
Options:

  1. Continue using :ui strings for common terms (current approach is acceptable)
  2. Duplicate to testharness strings.xml for complete independence

Not a blocker - current approach is reasonable for a test harness.


Testing

Test Coverage: 94.4% patch coverage with 65 missing lines is excellent for initial implementation.

⚠️ Finding 8: Low Coverage Areas Identified by Codecov

  • CredentialTestManagerImpl: Key integration point with Android Credential Manager
  • Navigation files: 33-55% coverage (author plans to add @OmitFromCoverage - acceptable)
  • MainViewModel: 62.5% coverage (empty sealed classes scenario)
Recommendation

Add integration tests for CredentialTestManagerImpl success paths before merge to verify Credential Manager API integration. Current tests cover error handling well but lack happy path validation.

Alternatively, document that manual testing coverage is sufficient for a test harness module.


Security

Checkmarx Findings Review:

  • Privacy_Violation (12 findings): False positives - test data in unit tests using "SecurePassword123!"
  • Use_of_Hardcoded_Password (9 findings): False positives - same test data
  • All findings are in test files - no production security concerns

Summary

Strong implementation following Bitwarden Android patterns. Main concerns:

  1. AndroidManifest configChanges - Needs orientation|screenSize added (see inline comment)
  2. ⚠️ Edge-to-edge padding - Multiple screens have scrolling padding issue (see inline comment)
  3. 💭 Human reviewer feedback - Several UI/code quality items remain unaddressed

Recommendation: Address AndroidManifest and edge-to-edge padding issues before merge. Other findings are minor improvements that can be addressed in follow-up if needed.


Introduces a new standalone :testharness Android application module for
end-to-end validation of Bitwarden's Credential Manager provider and
Autofill framework implementations.

Purpose:
The test harness acts as a credential consumer client, allowing developers
to trigger and verify all credential operations that Bitwarden supports as
a provider without relying on external websites or applications.

Supported Test Flows:
- Password Creation: CreatePasswordRequest via Credential Manager
- Password Retrieval: GetPasswordOption via Credential Manager
- Passkey Creation: CreatePublicKeyCredentialRequest (FIDO2)
- Passkey Authentication: GetPublicKeyCredentialOption (FIDO2)
- Hybrid Operations: Combined password/passkey retrieval flows
- Origin Parameter Testing: Privileged app simulation with custom origins
- Autofill Framework: Placeholder for future autofill service testing

Architecture:
- MVVM + UDF: BaseViewModel with State/Action/Event patterns
- Hilt DI: Full dependency injection throughout all layers
- Jetpack Compose: Material 3 UI with BitwardenTheme integration
- Navigation: Multi-screen architecture matching :app and :authenticator
- Error Handling: Sealed Result classes, no exception-based handling

Module Structure:
- Activity layer: MainActivity with theme management
- Navigation: RootNavScreen orchestrating all test flows
- Data layer: CredentialTestManager wrapping AndroidX Credentials APIs
- UI layer: Feature screens for each credential operation type
- Test coverage: Comprehensive unit tests for all ViewModels and Screens

Build Configuration:
- Added :testharness to settings.gradle.kts
- Integrated with detekt static analysis
- Integrated with kover code coverage reporting
- API 28+ requirement (AndroidX Credentials with Play Services)

Requirements:
- Android API 28+
- Bitwarden app installed as credential provider
- Google Play Services (for API 28-33 compatibility)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
SaintPatrck and others added 6 commits November 12, 2025 10:38
This commit addresses UI layout issues on testharness screens, particularly on devices with smaller displays where content could be pushed off-screen or overflow when the software keyboard is visible.

The primary change is removing fixed heights and weights from the result `OutlinedTextField` components across multiple screens. These modifiers were making the text fields inflexible, preventing the layout from shrinking to accommodate the keyboard. By removing them, the text fields now dynamically resize based on their content, allowing the entire screen to scroll when necessary.

Specific changes:
- Removed fixed height and weight modifiers from result text fields in `CreatePasswordScreen`, `GetPasskeyScreen`, `GetPasswordScreen`, `CreatePasskeyScreen`, and `GetPasswordOrPasskeyScreen` to allow them to resize with their content.
- Added vertical scrolling to `GetPasswordOrPasskeyScreen` to ensure all fields remain accessible when the keyboard is open.
- Added bottom navigation bar padding to the `LandingScreen` to prevent the last button from being obscured by system navigation gestures.
This commit refactors the testing for `CredentialTestManagerImpl` by replacing the existing limited test file with a comprehensive new suite that covers all public methods and their various outcomes.

The new test suite, `CredentialTestManagerTest`, provides detailed coverage for creating and retrieving both passwords and passkeys. It uses nested test classes for better organization and clarity. Key scenarios tested include successful operations (with and without an origin), user cancellations, API exceptions, and unexpected response types, ensuring the manager's logic is robust across different credential management flows.

Specific changes:
- Deleted the old, sparsely populated `CredentialTestManagerImplTest.kt`.
- Created `CredentialTestManagerTest.kt` with comprehensive unit tests for:
  - `createPassword`
  - `getPassword`
  - `createPasskey`
  - `getPasskey`
  - `getPasswordOrPasskey`
- Added tests for success, cancellation, and error states for each method.
- Implemented mocking for various `androidx.credentials` classes and exceptions to simulate different API responses.
Exclude navigation boilerplate from coverage analysis as these files
contain primarily routing logic that provides minimal value when tested
in isolation.

Files annotated:
- AutofillPlaceholderNavigation.kt
- CreatePasswordNavigation.kt
- CreatePasskeyNavigation.kt
- CredentialManagerListNavigation.kt
- GetPasskeyNavigation.kt
- GetPasswordNavigation.kt
- GetPasswordOrPasskeyNavigation.kt
- LandingNavigation.kt

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Create WebAuthnJsonBuilder utility class to separate WebAuthn JSON
generation from credential management logic, as suggested in PR review.

Changes:
- Add WebAuthnJsonBuilder.kt with buildPasskeyCreationJson and
  buildPasskeyAuthenticationJson methods
- Update CredentialTestManagerImpl to use WebAuthnJsonBuilder
- Remove private JSON building methods from CredentialTestManagerImpl
- Remove CHALLENGE_SEED_SIZE constant (moved to WebAuthnJsonBuilder)

This improves separation of concerns and makes JSON building logic
independently testable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
This commit addresses compiler warnings for unused exception variables in cancellation catch blocks. The exception variable `e` was declared but never used in `CreateCredentialCancellationException` and `GetCredentialCancellationException` handlers.

The variable `e` has been replaced with `_` to signify that it is intentionally unused, resolving the warnings and improving code clarity.
Add the `@OmitFromCoverage` annotation to the `WebAuthnJsonBuilder` test harness utility. This object is used for generating test data and is not part of the production application code, so it should be excluded from code coverage metrics.

Additionally, add warning comments to the `buildCreationRequest` and `buildAuthenticationRequest` methods, clarifying that the simplified challenge generation is for testing purposes only and not suitable for production use.
navigation<AutofillGraphRoute>(
startDestination = AutofillPlaceholderRoute,
) {
composable<AutofillPlaceholderRoute> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally we would have a AutofillPlaceholderNavigation file to put the route and destination.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I see what happened. Maybe we can still break inner destination out to a separate function.

Additionally, it should use the composableWithRootPushTransitions helper, right?

SaintPatrck and others added 3 commits November 17, 2025 12:40
Adds navigationBarsPadding Spacer at the bottom of:
- CreatePasswordScreen
- GetPasswordScreen

This ensures proper edge-to-edge display support and prevents
content from being obscured by system navigation bars,
maintaining consistency with other screens in the testharness.

Addresses PR #6159 review feedback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Remove Arrangement.spacedBy() patterns and replace with explicit
Spacer components throughout testharness screens:
- Remove spacedBy(16.dp) from main Columns
- Add explicit Spacer(Modifier.height(16.dp)) between elements
- Remove nested Columns used only for button spacing
- Use explicit Spacer(Modifier.height(12.dp)) between buttons

This provides better flexibility, clearer intent, and easier
customization of individual spacing values. Improves readability
by making all spacing explicit rather than implicit.

Addresses PR #6159 review feedback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
This commit refactors several screens within the `testharness` module to improve code consistency and align with standard UI patterns.

The primary changes include:
*   Consolidating composable parameters into a single `state` object, simplifying the function signatures of `CreatePasskeyScreenContent` and its preview.
*   Replacing hardcoded horizontal padding (`padding(horizontal = 16.dp)`) with the `standardHorizontalMargin()` modifier for consistent layout spacing across various test harness screens.
*   Removing redundant vertical padding from list screens (`LandingScreen`, `CredentialManagerListScreen`) as spacing is handled by inner components.
*   Deleting an unused `Clock` provider from the `CredentialTestManagerModule`.
@SaintPatrck SaintPatrck requested a review from a team as a code owner November 18, 2025 13:50
Inject a fixed `Clock` into the Credential-related view models (`CreatePasskeyViewModel`, `GetPasskeyViewModel`, `CreatePasswordViewModel`, `GetPasswordViewModel`, and `GetPasswordOrPasskeyViewModel`).

This ensures that any time-dependent logic within these view models becomes deterministic, preventing potential flakiness in the corresponding tests. Previously, the view models relied on the system clock, which could lead to unpredictable behavior during test execution. This change makes the tests more reliable and repeatable.
Simplify the `compileOptions` block in `testharness/build.gradle.kts`. This change replaces the manual construction of the `JavaVersion` enum from a string with a more direct and readable method call.

The previous implementation manually parsed the version string from `libs.versions.jvmTarget`, replaced the dot with an underscore, and prepended "VERSION_" to match the `JavaVersion` enum name. The new implementation achieves the same result by directly passing the version string to the `sourceCompatibility` and `targetCompatibility` methods, improving code clarity and maintainability.
@github-actions
Copy link
Contributor

Warning

@SaintPatrck Uploading code coverage report failed. Please check the "Upload to codecov.io" step of Process Test Reports job for more details.

Refactor the Credential Manager list navigation to use root push transitions and improve the screen's layout handling of system insets.

- Switch `CredentialManagerListRoute` to use `composableWithRootPushTransitions` instead of the standard `composable` builder to ensure consistent transition animations.
- Extract the screen instantiation into a private `credentialManagerListDestination` composable helper.
- Add `navigationBarsPadding` and vertical spacing to the bottom of `CredentialManagerListScreen` to prevent content from being obscured by the system navigation bar.
- Apply minor formatting improvements to the event handling logic in `CredentialManagerListScreen`.
Migrate the `testharness` module from the `com.x8bit.bitwarden.testharness` package to `com.bitwarden.testharness` to align with the project's standard package naming conventions.

- Move all source and test files to the new `com.bitwarden.testharness` directory structure and update all import statements.
- Update `namespace` and `applicationId` in `testharness/build.gradle.kts`.
- Update package references in `testharness/proguard-rules.pro`.
- Replace local `R.string.clear` usage with the shared `BitwardenString.clear` resource in `CreatePasskeyScreen` and `CreatePasswordScreen`.
- Add a top spacer to the content list in `CredentialManagerListScreen` for improved layout spacing.
- Improve code formatting by adding newlines between `when` expression branches in `CredentialTestManagerImpl`, `CredentialTestManagerTest`, and various ViewModels.
Refactor navigation logic in the `testharness` module to use consistent transition patterns and improve UI scrolling behavior. Additionally, replace hardcoded strings with localized resources for accessibility content descriptions.

- Refactor `AutofillPlaceholderNavigation` and `CredentialManagerListNavigation` to encapsulate screen definitions within `NavGraphBuilder` extension functions. These functions now directly utilize `composableWithRootPushTransitions`, ensuring consistent transition animations and cleaner graph definitions.
- Update `CredentialManagerListScreen` to attach the `nestedScrollConnection` from the `scrollBehavior` to the `BitwardenScaffold`. This enables proper nested scrolling interactions with the pinned top app bar.
- Replace the hardcoded "Back" content description with `stringResource(BitwardenString.back)` across all feature screens (`CreatePasswordScreen`, `CreatePasskeyScreen`, `GetPasswordScreen`, `GetPasskeyScreen`, `GetPasswordOrPasskeyScreen`, and `CredentialManagerListScreen`) to ensure consistency and proper localization support.
- Delete the unused helper script `.claude/skills/reviewing-changes/scripts/detect-threads.sh`.

<activity
android:name=".MainActivity"
android:configChanges="uiMode"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing critical configuration changes

The configChanges attribute must include orientation|screenSize in addition to uiMode. Without these:

  • Device rotation will destroy and recreate the activity
  • Multi-window/foldable device changes will destroy and recreate the activity
  • SavedStateHandle usage alone doesn't prevent the performance cost and visual disruption
Required fix
android:configChanges="orientation|screenSize|uiMode"

Why this matters:

  • orientation: Handles device rotation without recreation
  • screenSize: Handles multi-window mode and foldable device configuration changes
  • uiMode: Handles dark/light theme changes (already present)

The main :app module follows this same pattern. See app/src/main/AndroidManifest.xml for reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional. We are only concerned with uiMode changes.

)

Spacer(modifier = Modifier.height(16.dp))
Spacer(modifier = Modifier.navigationBarsPadding())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 NavigationBarsPadding inside scrolling content breaks edge-to-edge

The navigationBarsPadding() modifier should not be inside the scrolling Column as a Spacer. This causes the padding to scroll with content, breaking edge-to-edge display.

Standard pattern from :app module

Apply padding to the Column modifier itself:

Column(
    modifier = Modifier
        .fillMaxSize()
        .imePadding()
        .navigationBarsPadding()  // Move here
        .verticalScroll(rememberScrollState()),
) {
    // ... content ...
    
    Spacer(modifier = Modifier.height(16.dp))
    // Remove: Spacer(modifier = Modifier.navigationBarsPadding())
}

Applies to these screens:

  • CreatePasswordScreen.kt:148
  • CreatePasskeyScreen.kt (similar pattern)
  • GetPasswordScreen.kt (similar pattern)
  • GetPasskeyScreen.kt (similar pattern)
  • GetPasswordOrPasskeyScreen.kt (similar pattern)
  • CredentialManagerListScreen.kt (similar pattern)

Reference: See vault item screens in :app module for correct edge-to-edge implementation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude We want the padding to scroll with the content

Copy link
Contributor

@claude claude bot Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude finished @david-livefront's task —— View job


Clarification Acknowledged

Thank you for the clarification, David. I understand now that having the navigationBarsPadding() scroll with the content is the intended behavior for this test harness.

I'm withdrawing my previous comment about this being an edge-to-edge display issue. The current implementation with Spacer(modifier = Modifier.navigationBarsPadding()) inside the scrolling Column is correct for the desired UX in this context.

This pattern applies across the testharness screens (CreatePasswordScreen, CreatePasskeyScreen, GetPasswordScreen, etc.) and is intentional.


}

private fun timestamp(): String {
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Hardcoded date format pattern

The timestamp format "HH:mm:ss" is hardcoded and not locale-aware. For a test harness, this is likely intentional for consistent log parsing, but should be documented.

Add documentation
private fun timestamp(): String {
    // Fixed format for consistent test output parsing across locales
    val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
    return clock.instant()
        .atZone(ZoneId.systemDefault())
        .format(formatter)
        .let { "[$it]" }
}

If locale-aware formatting is desired instead:

private fun timestamp(): String {
    val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)
    return clock.instant()
        .atZone(ZoneId.systemDefault())
        .format(formatter)
        .let { "[$it]" }
}

Applies to: All ViewModel files with timestamp() functions (CreatePasskeyViewModel, GetPasswordViewModel, GetPasskeyViewModel, GetPasswordOrPasskeyViewModel)

Copy link
Contributor

@aj-rosado aj-rosado left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work @SaintPatrck. LGTM 👏

@SaintPatrck
Copy link
Contributor Author

Thanks @aj-rosado and @david-livefront.

@SaintPatrck SaintPatrck added this pull request to the merge queue Nov 21, 2025
Merged via the queue into main with commit a395f28 Nov 21, 2025
43 of 51 checks passed
@SaintPatrck SaintPatrck deleted the testharness-app branch November 21, 2025 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants